﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WCAD.Kean
{
    public class Explosions
    {
        [CommandMethod("EB")]
        public void EB()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            if (doc == null)
                return;
            var ed = doc.Editor;
            var db = doc.Database;
            // Ask the user to select the block
            var peo = new PromptEntityOptions("\nSelect block to explode");
            peo.SetRejectMessage("Must be a block.");
            peo.AddAllowedClass(typeof(BlockReference), false);
            var per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;
            using (var tr = db.TransactionManager.StartTransaction())
            {
                // Call our explode function recursively, starting
                // with the top-level block reference
                // (you can pass false as a 4th parameter if you
                // don't want originating entities erased)
                ExplodeBlock(tr, db, per.ObjectId);
                tr.Commit();
            }
        }
        private void ExplodeBlock(Transaction tr, Database db, ObjectId id, bool erase = true)
        {
            // Open out block reference - only needs to be readable
            // for the explode operation, as it's non-destructive
            var br = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
            // We'll collect the BlockReferences created in a collection
            var toExplode = new ObjectIdCollection();
            // Define our handler to capture the nested block references
            ObjectEventHandler handler =(s, e) =>
              {
                  if (e.DBObject is BlockReference)
                  {
                      toExplode.Add(e.DBObject.ObjectId);
                  }
              };
            // Add our handler around the explode call, removing it
            // directly afterwards
            db.ObjectAppended += handler;
            br.ExplodeToOwnerSpace();
            db.ObjectAppended -= handler;
            // Go through the results and recurse, exploding the
            // contents
            foreach (ObjectId bid in toExplode)
            {
                ExplodeBlock(tr, db, bid, erase);
            }
            // We might also just let it drop out of scope
            toExplode.Clear();
            // To replicate the explode command, we're delete the
            // original entity
            if (erase)
            {
                br.UpgradeOpen();
                br.Erase();
                br.DowngradeOpen();
            }
        }

        [CommandMethod("EXP", CommandFlags.UsePickSet)]

        public void EXP()

        {

            Document doc =

                Application.DocumentManager.MdiActiveDocument;

            Database db = doc.Database;

            Editor ed = doc.Editor;



            // Ask user to select entities



            PromptSelectionOptions pso =

              new PromptSelectionOptions();

            pso.MessageForAdding = "\nSelect objects to explode: ";

            pso.AllowDuplicates = false;

            pso.AllowSubSelections = true;

            pso.RejectObjectsFromNonCurrentSpace = true;

            pso.RejectObjectsOnLockedLayers = false;



            PromptSelectionResult psr = ed.GetSelection(pso);

            if (psr.Status != PromptStatus.OK)

                return;



            // Check whether to erase the original(s)



            bool eraseOrig = false;



            if (psr.Value.Count > 0)

            {

                PromptKeywordOptions pko =

                  new PromptKeywordOptions("\nErase original objects?");

                pko.AllowNone = true;

                pko.Keywords.Add("Yes");

                pko.Keywords.Add("No");

                pko.Keywords.Default = "No";



                PromptResult pkr = ed.GetKeywords(pko);

                if (pkr.Status != PromptStatus.OK)

                    return;



                eraseOrig = (pkr.StringResult == "Yes");

            }



            Transaction tr =

              db.TransactionManager.StartTransaction();

            using (tr)

            {

                // Collect our exploded objects in a single collection



                DBObjectCollection objs = new DBObjectCollection();



                // Loop through the selected objects



                foreach (SelectedObject so in psr.Value)

                {

                    // Open one at a time



                    Entity ent =

                      (Entity)tr.GetObject(

                        so.ObjectId,

                        OpenMode.ForRead

                      );



                    // Explode the object into our collection



                    ent.Explode(objs);



                    // Erase the original, if requested



                    if (eraseOrig)

                    {

                        ent.UpgradeOpen();

                        ent.Erase();

                    }

                }



                // Now open the current space in order to

                // add our resultant objects



                BlockTableRecord btr =

                  (BlockTableRecord)tr.GetObject(

                    db.CurrentSpaceId,

                    OpenMode.ForWrite

                  );



                // Add each one of them to the current space

                // and to the transaction



                foreach (DBObject obj in objs)

                {

                    Entity ent = (Entity)obj;

                    btr.AppendEntity(ent);

                    tr.AddNewlyCreatedDBObject(ent, true);

                }



                // And then we commit



                tr.Commit();

            }

        }
    }
}
